﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Threading;
using System.Text.RegularExpressions;
using MRG.Controls.UI;
using FreeBroker.Properties;
using Updater;

namespace FreeBroker
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            GroupBox[] boxes = new GroupBox[] { groupBox1, groupBox2, groupBox3, groupBox4, groupBox5, groupBox6 };
            for (int i = 0; i < boxes.Length; i++)
            {
                BackgroundWorker worker = new BackgroundWorker();
                worker.WorkerSupportsCancellation = true;
                worker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
                worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
                boxes[i].Tag = worker;
            }
            
         }

        private BrokerObject[] brokerObs;

        private void button1_Click(object sender, EventArgs e)
        {
            //godmodeRequest("29030400", this.pictureBox2);
            //godmodeRequest("7257600", this.pictureBox1);
            //godmodeRequest("14515200", this.pictureBox3);
            //godmodeRequest("14515200", this.pictureBox6);
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            MainForm.running = false;
            Settings.Default.Search1 = this.comboBox1.Text;
            Settings.Default.Search2 = this.comboBox2.Text;
            Settings.Default.Search3 = this.comboBox3.Text;
            Settings.Default.Search4 = this.comboBox4.Text;
            Settings.Default.Search5 = this.comboBox5.Text;
            Settings.Default.Search6 = this.comboBox6.Text;
            Settings.Default.autoUpdate = this.buttonAutoUpdate.Checked;
            Settings.Default.Save();
        }

        private void MainForm_Shown(object sender, EventArgs e)
        {
            //UpdateStarter update = new UpdateStarter();
            //update.Update(Program.info, true);

            MainForm.running = true;
            MainForm.autoUpdate = Settings.Default.autoUpdate;
            this.buttonAutoUpdate.Checked = running;
            
            this.comboBox1.Text = Settings.Default.Search1;
            this.comboBox2.Text = Settings.Default.Search2;
            this.comboBox3.Text = Settings.Default.Search3;
            this.comboBox4.Text = Settings.Default.Search4;
            this.comboBox5.Text = Settings.Default.Search5;
            this.comboBox6.Text = Settings.Default.Search6;

            this.brokerObs = new BrokerObject[6];
            this.brokerObs[0] = new BrokerObject(this.groupBox1);
            this.brokerObs[1] = new BrokerObject(this.groupBox2);
            this.brokerObs[2] = new BrokerObject(this.groupBox3);
            this.brokerObs[3] = new BrokerObject(this.groupBox4);
            this.brokerObs[4] = new BrokerObject(this.groupBox5);
            this.brokerObs[5] = new BrokerObject(this.groupBox6);

            processManager.RunWorkerAsync(brokerObs.Length);
        }

        private static bool running = false;

        private static bool autoUpdate = false;

        private List<int> jobQueue = new List<int>();

        private static AutoResetEvent locked = new AutoResetEvent(true);

        private void processManager_DoWork(object sender, DoWorkEventArgs e)
        {
            int length = (int)e.Argument;

            int minutes = (int)Settings.Default.AutoUpdateMinutes;
            int waitSeconds = minutes * 60;
            bool firstRun = true;
            DateTime startTime = DateTime.Now;

            while (running)
            {
                DateTime currentTime = DateTime.Now;
                TimeSpan span = currentTime - startTime;
                int elapsedSecs = (int)span.TotalSeconds;
                if (autoUpdate && (elapsedSecs > waitSeconds || firstRun) )
                {
                    for (int i = 0; i < length; i++)
                    {
                        // Iterate through processes
                        if (!this.jobQueue.Contains(i))
                        {
                            BrokerObject brokerObj = this.brokerObs[i];
                            if (brokerObj != null || brokerObj.AssignedComboBox != null)
                            {
                                string text = GetComboText(brokerObj.AssignedComboBox, brokerObj.AssignedLoadingCircle);
                                if (text != null && text.Length > 0)
                                {
                                    this.jobQueue.Add(i);
                                }
                            }
                        }
                    }
                }
                
                // Check if manually added jobs are existing in queue
                if (this.jobQueue.Count > 0)
                {
                    List<int> queueCopy = new List<int>();
                    queueCopy.AddRange(this.jobQueue);
                    this.jobQueue.Clear();
                    foreach (int index in queueCopy)
                    {
                        // Start asynchron search process
                        try
                        {
                            startSearch(index);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                    }
                }

                firstRun = false;
                Thread.Sleep(1000);
            }

            Console.WriteLine("Closing Process Manager...");
        }

        private void buttonSearch_Click(object sender, EventArgs e)
        {
            Button button = (Button)sender;
            string indexStr = (string)button.Tag;
            int index = int.Parse(indexStr);
            if (!this.jobQueue.Contains(index))
            {
                BrokerObject brokerObj = this.brokerObs[index];
                if (brokerObj != null || brokerObj.AssignedComboBox != null)
                {
                    string text = GetComboText(brokerObj.AssignedComboBox, brokerObj.AssignedLoadingCircle);
                    if (text != null && text.Length > 0)
                    {
                        this.jobQueue.Add(index);
                    }
                    else
                    {
                        MessageBox.Show("Es wurde keine Nummer eingegeben.");
                    }
                }
            }
        }

        private void startSearch(int index)
        {
            BrokerObject brokerObj = this.brokerObs[index];
            brokerObj.BrokerIndex = index;
            if (brokerObj == null || brokerObj.AssignedGroupBox == null)
            {
                return;
            }

            Console.WriteLine("Locking thread...");
            locked.WaitOne(60000, true);

            GroupBox box = brokerObj.AssignedGroupBox;
            Console.WriteLine("Running process <" + box.Name + ">");

            BackgroundWorker worker = (BackgroundWorker)box.Tag;
            while (worker.IsBusy)
            {
                worker.CancelAsync();
                Thread.Sleep(1000);
            }
            worker.RunWorkerAsync(brokerObj);
        }

        /// <summary>
        ///     Returns the combo box text (previously entering the right thread).
        ///     Starts the loading circle fade in process.
        /// </summary>
        /// <param name="combo"></param>
        /// <param name="circle"></param>
        /// <returns></returns>
        private string GetComboText(ComboBox combo, LoadingCircle circle)
        {
            if (combo.InvokeRequired || circle.InvokeRequired)
            {
                object output = combo.Invoke(new ComboTextDelegate(GetComboText), new object[] { combo, circle });
                return output != null ? (string)output : null;
            }
            // The right thread, start execution
            if (combo.Text != null && combo.Text.Length > 0)
            {
                circle.FadeIn();
                return combo.Text;
            }
            return null;
        }

        private delegate string ComboTextDelegate(ComboBox combo, LoadingCircle circle);


        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            BrokerObject obj = (BrokerObject)e.Argument;

            string query = GetComboText(obj.AssignedComboBox, obj.AssignedLoadingCircle);
            
            if (query != null && query.Length > 0)
            {
                Communication com = new Communication();
                obj.Symbol = com.comdirectPostSearch(query);
                if (obj.Symbol != null && obj.Symbol.Length > 0)
                {
                    try
                    {
                        obj.chartThumbnail = com.comdirectImage("http://isht.comdirect.de/charts/small.ewf.chart?hist=1y&sSym=" + obj.Symbol, "");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }
                
                e.Result = obj;
            }
            
        }

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            BrokerObject obj = (BrokerObject)e.Result;
            if (obj != null)
            {
                SetAttribs(obj);
                StopCircle(obj.AssignedLoadingCircle);
                this.brokerObs[obj.BrokerIndex] = obj;
            }

            Console.WriteLine("Unlocking thread...");
            locked.Set();
        }

        private void SetAttribs(BrokerObject broker)
        {
            if (broker == null)
            {
                return;
            }
            if (broker.AssignedPictureBox.InvokeRequired)
            {
                broker.AssignedPictureBox.Invoke(new SetAttribsDelegate(SetAttribs), new object[] { broker });
                return;
            }
            broker.AssignedPictureBox.Image = broker.chartThumbnail;
            broker.AssignedGroupBox.Text = broker.Name;
            StringBuilder builder = new StringBuilder();
            builder.AppendLine("Name: " + broker.Name);
            builder.AppendLine("ISIN: " + broker.Isin);
            builder.AppendLine(" WKN: " + broker.Wkn);
            builder.AppendLine("Symbol: " + broker.Symbol);
            builder.AppendLine("Gattung: " + broker.Type);
            builder.AppendLine("Land: " + broker.Country);
            builder.AppendLine("Link: " + broker.Url);
            toolTip.SetToolTip(broker.AssignedPictureBox, builder.ToString());
        }
        private delegate void SetAttribsDelegate(BrokerObject broker);

        private void StopCircle(LoadingCircle circle)
        {
            if (circle.InvokeRequired)
            {
                circle.Invoke(new StopCircleDelegate(StopCircle), new object[] { circle });
                return;
            }
            circle.FadeOut();
        }
        private delegate void StopCircleDelegate(LoadingCircle circle);

        private void buttonSearchResults_Click(object sender, EventArgs e)
        {
            StreamReader sr = new StreamReader(@"E:\response.html");
            string content = sr.ReadToEnd();
            Regex regex = new Regex("<tr onclick=\"location\\.href='(.+?)'.+\r\n.+?<td>.+?>(.+?)</a>.+(\r\n)*.+?>(.+?)<.+(\r\n)*.+?>(.+?)<.+(\r\n)*.+?>(.+?)<.+");
            MatchCollection col = regex.Matches(content);
            //int i = 0;
            BrokerObject[] results = new BrokerObject[col.Count];
            foreach (Match match in col)
            {
                //BrokerObject res = new BrokerObject();
                //res.link = match.Groups[1].Value.Trim();
                //res.name = match.Groups[2].Value.Trim();
                //res.isin = match.Groups[4].Value.Trim();
                //res.wkn = match.Groups[6].Value.Trim();
                //res.symbol = match.Groups[8].Value.Trim();
                //results[i] = res;
                //i++;
            }
            Console.WriteLine();
        }

        private void buttonInfoPageParse_Click(object sender, EventArgs e)
        {
            StreamReader sr = new StreamReader(@"E:\response2.html");
            string content = sr.ReadToEnd();
            Regex regex = new Regex("<h1>(.+?)</h1>(.*?[\r\n]*.*?)*?WKN&nbsp;<strong>(.*?)</strong>(.*?[\r\n]*.*?)*?ISIN&nbsp;<strong>(.*?)</strong>(.*?[\r\n]*.*?)*?Symbol&nbsp;<strong>(.*?)</strong>(.*?[\r\n]*.*?)*?Gattung:(.*?[\r\n]*.*?)*?<td.*?>(.+?)</td(.*?[\r\n]*.*?)*?Land:(.*?[\r\n]*.*?)*?<td>(.*?)</td");
            MatchCollection col = regex.Matches(content);
            foreach (Match match in col)
            {
                Console.WriteLine("-------------------------------------");
                Console.WriteLine("Name: " + match.Groups[1].Value);
                Console.WriteLine("ISIN: " + match.Groups[5].Value);
                Console.WriteLine(" WKN: " + match.Groups[3].Value);
                Console.WriteLine("Symbol: " + match.Groups[7].Value);
                Console.WriteLine("Gattung: " + match.Groups[10].Value);
                Console.WriteLine("Land: " + match.Groups[13].Value);
            }
        }

        private void pictureBox_Click(object sender, EventArgs e)
        {
            PictureBox pb = (PictureBox)sender;
            GroupBox box = (GroupBox)pb.Parent;
            if (pb.Image != null && this.brokerObs != null)
            {
                int procNumber = box.TabIndex - 1;
                DetailView tv = new DetailView(this.brokerObs[procNumber],procNumber);
                tv.Show();
            }
            
        }

        private int procCounter = 0;

        private void buttonNewProcess_Click(object sender, EventArgs e)
        {
            int x = (this.procCounter * 282);
            int y = 0;
            //
            // Combo Button
            //
            ComboBox combo = new ComboBox();
            combo.FormattingEnabled = true;
            combo.Location = new Point(x + 17, y + 19);
            combo.Name = "comboBox" + this.procCounter;
            combo.Size = new Size(185, 21);
            // 
            // PictureBox
            //
            PictureBox picBox = new PictureBox();
            picBox.Anchor = ((AnchorStyles)((((AnchorStyles.Top | AnchorStyles.Bottom) | AnchorStyles.Left) | AnchorStyles.Right)));
            picBox.Location = new Point(x + 17, y + 46);
            picBox.Name = "pictureBox" + this.procCounter;
            picBox.Size = new Size(165, 45);
            picBox.BorderStyle = BorderStyle.Fixed3D;
            picBox.SizeMode = PictureBoxSizeMode.StretchImage;
            picBox.TabStop = false;
            // 
            // Button
            //
            Button button = new Button();
            button.Location = new Point(x + 208, y + 18);
            button.Name = "button" + this.procCounter;
            button.Size = new Size(63, 21);
            button.Text = "Search";
            button.UseVisualStyleBackColor = true;
            //
            // Group Box
            //
            GroupBox box = new GroupBox();
            box.Anchor = (AnchorStyles)(AnchorStyles.Top | AnchorStyles.Left);
            box.Controls.Add(combo);
            box.Controls.Add(picBox);
            box.Controls.Add(button);
            box.Location = new Point(x + 15, y + 22);
            box.Name = "procBox" + this.procCounter;
            box.Size = new Size(282, 226);
            box.TabStop = false;
            box.Text = "Process " + (this.procCounter + 1);
            box.Refresh();
            this.panel.Controls.Add(box);
            this.panel.AutoScrollMinSize = new Size(x + 282, y + 226);

            this.procCounter++;
        }

        private void buttonAutoUpdate_Click(object sender, EventArgs e)
        {
            RadioButton but = (RadioButton)sender;
            MainForm.autoUpdate = !but.Checked;
            but.Checked = !but.Checked;
        }

        private void buttonTestComDirectSearch_Click(object sender, EventArgs e)
        {
            Communication com = new Communication();
            string test = com.comdirectPostSearch("882340");
            Image img = com.comdirectImage("http://isht.comdirect.de/charts/small.ewf.chart?hist=1y&sSym=" + test, "");
            pictureBox1.Image = img;
        }

        private void btnUpdatesList_Click(object sender, EventArgs e)
        {
            //UpdateStarter update = new UpdateStarter();
            //update.Overview(Program.info);
        }

        private void button4_Click(object sender, EventArgs e)
        {
            DetailView tv = new DetailView(this.brokerObs[0],0);
            tv.Show();
        }

    }
}
